package com.kuaiyin.utils;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import org.springframework.beans.BeanUtils;

import java.util.List;
import java.util.function.Consumer;
import java.util.stream.Collectors;

/**
 * MyBatis-Plus 查询工具类（支持分页/全量查询 + 自动VO转换）
 */
public class PageHelper {

    // ------------------- 分页查询方法 ------------------- //

    /**
     * 基础分页查询（无查询条件）
     * @param pageNum  当前页码（从1开始）
     * @param pageSize 每页记录数
     * @param mapper   MyBatis-Plus Mapper接口
     * @return 分页结果(包含数据列表和总条数)
     * @param <T> 实体类型
     */
    public static <T> PageResult<T> query(int pageNum, int pageSize, BaseMapper<T> mapper) {
        return query(pageNum, pageSize, mapper, null);
    }

    /**
     * 带条件的分页查询
     * @param pageNum   当前页码（从1开始）
     * @param pageSize  每页记录数
     * @param mapper    MyBatis-Plus Mapper接口
     * @param condition 查询条件构造器（Lambda表达式）
     * @return 分页结果(包含数据列表和总条数)
     * @param <T> 实体类型
     */
    public static <T> PageResult<T> query(
            int pageNum,
            int pageSize,
            BaseMapper<T> mapper,
            Consumer<LambdaQueryWrapper<T>> condition) {

        Page<T> page = executeQuery(pageNum, pageSize, mapper, condition);
        return PageResult.of(page.getRecords(), page.getTotal(), pageNum, pageSize);
    }

    /**
     * 带自动VO转换的分页查询（无查询条件）
     * @param pageNum  当前页码（从1开始）
     * @param pageSize 每页记录数
     * @param mapper   MyBatis-Plus Mapper接口
     * @param voClass  VO类类型
     * @return 分页结果(包含VO列表和总条数)
     * @param <T> 实体类型
     * @param <V> VO类型
     */
    public static <T, V> PageResult<V> queryWithVo(
            int pageNum,
            int pageSize,
            BaseMapper<T> mapper,
            Class<V> voClass) {

        return queryWithVo(pageNum, pageSize, mapper, voClass, null);
    }

    /**
     * 带条件和VO转换的分页查询（最常用）
     * @param pageNum   当前页码（从1开始）
     * @param pageSize  每页记录数
     * @param mapper    MyBatis-Plus Mapper接口
     * @param voClass   VO类类型
     * @param condition 查询条件构造器（Lambda表达式）
     * @return 分页结果(包含VO列表和总条数)
     * @param <T> 实体类型
     * @param <V> VO类型
     */
    public static <T, V> PageResult<V> queryWithVo(
            int pageNum,
            int pageSize,
            BaseMapper<T> mapper,
            Class<V> voClass,
            Consumer<LambdaQueryWrapper<T>> condition) {

        PageResult<T> result = query(pageNum, pageSize, mapper, condition);
        return result.map(entity -> convertToVo(entity, voClass));
    }

    // ------------------- 全量查询方法 ------------------- //

    /**
     * 查询全部数据（不分页，无查询条件）
     * @param mapper MyBatis-Plus Mapper接口
     * @return 实体列表
     * @param <T> 实体类型
     */
    public static <T> List<T> queryAll(BaseMapper<T> mapper) {
        return queryAll(mapper, null);
    }

    /**
     * 带条件的查询全部数据（不分页）
     * @param mapper    MyBatis-Plus Mapper接口
     * @param condition 查询条件构造器（Lambda表达式）
     * @return 实体列表
     * @param <T> 实体类型
     */
    public static <T> List<T> queryAll(
            BaseMapper<T> mapper,
            Consumer<LambdaQueryWrapper<T>> condition) {

        LambdaQueryWrapper<T> wrapper = new LambdaQueryWrapper<>();
        if (condition != null) {
            condition.accept(wrapper);
        }
        return mapper.selectList(wrapper);
    }

    /**
     * 带自动VO转换的查询全部数据（不分页，无查询条件）
     * @param mapper  MyBatis-Plus Mapper接口
     * @param voClass VO类类型
     * @return VO列表
     * @param <T> 实体类型
     * @param <V> VO类型
     */
    public static <T, V> List<V> queryAllWithVo(
            BaseMapper<T> mapper,
            Class<V> voClass) {

        return queryAllWithVo(mapper, voClass, null);
    }

    /**
     * 带条件和VO转换的查询全部数据（不分页）
     * @param mapper    MyBatis-Plus Mapper接口
     * @param voClass   VO类类型
     * @param condition 查询条件构造器（Lambda表达式）
     * @return VO列表
     * @param <T> 实体类型
     * @param <V> VO类型
     */
    public static <T, V> List<V> queryAllWithVo(
            BaseMapper<T> mapper,
            Class<V> voClass,
            Consumer<LambdaQueryWrapper<T>> condition) {

        List<T> entities = queryAll(mapper, condition);
        return entities.stream()
                .map(entity -> convertToVo(entity, voClass))
                .collect(Collectors.toList());
    }


    // ------------------- 私有方法 ------------------- //

    /**
     * 执行分页查询（核心方法）
     * @param pageNum   当前页码
     * @param pageSize  每页记录数
     * @param mapper    MyBatis-Plus Mapper接口
     * @param condition 查询条件
     * @return MyBatis-Plus 分页对象
     * @param <T> 实体类型
     */
    private static <T> Page<T> executeQuery(
            int pageNum,
            int pageSize,
            BaseMapper<T> mapper,
            Consumer<LambdaQueryWrapper<T>> condition) {

        LambdaQueryWrapper<T> wrapper = new LambdaQueryWrapper<>();
        if (condition != null) {
            condition.accept(wrapper);
        }
        return mapper.selectPage(new Page<>(pageNum, pageSize), wrapper);
    }


    /**
     * 实体转VO工具方法
     * @param entity  实体对象
     * @param voClass VO类类型
     * @return 转换后的VO对象
     * @param <T> 实体类型
     * @param <V> VO类型
     * @throws RuntimeException 如果转换失败
     */
    private static <T, V> V convertToVo(T entity, Class<V> voClass) {
        try {
            V vo = voClass.getDeclaredConstructor().newInstance();
            BeanUtils.copyProperties(entity, vo);
            return vo;
        } catch (Exception e) {
            throw new RuntimeException("VO转换失败", e);
        }
    }
}